# coding:utf-8
from pathlib import Path
from typing import Union, List, Any

from PIL import Image
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QFileDialog
from qfluentwidgets import GroupHeaderCardWidget, FluentIcon as FIF, BodyLabel, PrimaryPushButton, Slider, PushButton, \
    InfoBar, SwitchButton, SpinBox, setFont

from common import Icon
from components import BaseScrollArea, FileListSettingCard


def compressImage(
        files: Union[str, Path, List[str], List[Path]],
        save_dir: Union[str, Path] = None,
        size: tuple = None,
        keep_ratio: bool = True,
        quality: int = 75
):
    """
    压缩图片
    :param files:
    :param save_dir:
    :param size:
    :param keep_ratio:
    :param quality:
    :return:
    """
    if isinstance(files, (str, Path)):
        files = [files]
    if isinstance(save_dir, str):
        save_dir = Path(save_dir)
    for file in files:
        if isinstance(file, str):
            file = Path(file)
        if save_dir is None:
            save_dir = file.parent
        img = Image.open(file)
        suffix = img.format.lower()
        save_file = save_dir / f'{file.stem}_compressed.{suffix}'
        if keep_ratio:
            w, h = img.size
            w1, h1 = size
            size = (w1, int(w1 / w * h))
        img = img.resize(size)
        img.save(save_file, img.format, quality=quality, optimize=True)


class QualitySlider(QWidget):
    def __init__(self, parent: QWidget = None):
        super().__init__(parent)
        self.hBox = QHBoxLayout(self)
        self.qualityLabel = BodyLabel('0', self)
        self.qualitySlider = Slider(Qt.Orientation.Horizontal, self)

        self.qualitySlider.setRange(1, 100)
        self.qualitySlider.setSingleStep(1)
        self.qualitySlider.valueChanged.connect(lambda value: self.qualityLabel.setText(str(value)))
        self.qualitySlider.setValue(70)

        self.hBox.addWidget(self.qualityLabel)
        self.hBox.addWidget(self.qualitySlider)

    def value(self) -> int:
        return self.qualitySlider.value()

    def setValue(self, value: int) -> None:
        self.qualitySlider.setValue(value)


class SizeSettingWidget(QWidget):
    def __init__(self, parent: QWidget = None):
        super().__init__(parent)
        self.hBox = QHBoxLayout(self)
        self.widthSpinBox = SpinBox(self)
        self.spacer = BodyLabel('X', self)
        self.heightSpinBox = SpinBox(self)

        self.widthSpinBox.setRange(1, 100000)
        self.widthSpinBox.setSingleStep(100)
        self.widthSpinBox.setValue(1920)
        self.heightSpinBox.setRange(1, 100000)
        self.heightSpinBox.setSingleStep(100)
        self.heightSpinBox.setValue(1080)

        self.hBox.addWidget(self.widthSpinBox)
        self.hBox.addWidget(self.spacer)
        self.hBox.addWidget(self.heightSpinBox)

    def getSize(self) -> tuple[int, int]:
        return self.widthSpinBox.value(), self.heightSpinBox.value()


class CompressImageView(BaseScrollArea):
    IMAGE_SUFFIX = ['.jpg', '.png', '.jpeg', '.webp']

    title = '图片压缩'
    description = '压缩图片，降低图片体积，提高图片质量。'
    is_shortcut = True
    object_name = 'CompressImageView'
    icon = Icon.PHOTO_ZIP

    def __init__(self, parent: QWidget = None):
        super().__init__(parent)
        self.scrollLayout: QVBoxLayout
        self.savePath = ''
        self.titleLabel = BodyLabel('图片压缩', self)
        self.imageFileCard = FileListSettingCard(
            FIF.PHOTO,
            '图片列表',
            directory=f'图片文件 ({" *".join(self.IMAGE_SUFFIX)})',
            parent=self
        )
        self.groupHeaderCard = GroupHeaderCardWidget('压缩设置', self)
        self.startBtn = PrimaryPushButton(FIF.PLAY, '开始压缩', self)
        self.qualitySlider = QualitySlider(self)
        self.saveBtn = PushButton(FIF.FOLDER, '选择文件夹', self)
        self.keepRatioSwitch = SwitchButton(self)
        self.sizeSettingWidget = SizeSettingWidget(self)

        self.__initWidget()
        self.__connectSignals()

    def __initWidget(self):
        self.setObjectName('CompressImageView')
        self.setReturnVisible(True)
        setFont(self.titleLabel, 24)
        self.imageFileCard.setAddText('添加图片')
        self.keepRatioSwitch.setChecked(True)
        self.keepRatioSwitch.setText('保持比例')

        self.savePathGroup = self.groupHeaderCard.addGroup(
            FIF.SAVE_AS,
            '保存路径',
            '设置压缩后的图片保存路径, 留空则默认保存到原图片目录, 并对原图片进行重命名, 非空则保留原有文件名',
            self.saveBtn,
        )
        self.groupHeaderCard.addGroup(
            FIF.CONNECT,
            '压缩尺寸',
            '设置压缩后的图片尺寸, 留空则默认保持原图大小, 否则按比例缩放',
            self.sizeSettingWidget,
            stretch=1,
        )
        self.groupHeaderCard.addGroup(
            FIF.CHECKBOX,
            '保持比例',
            '是否保持压缩后的图片比例, 若不保持, 则按设置的尺寸缩放',
            self.keepRatioSwitch,
        )
        self.groupHeaderCard.addGroup(
            Icon.FPS,
            '压缩质量',
            '设置压缩质量, 值越高, 压缩后的图片质量越好, 但文件大小也会变大',
            self.qualitySlider,
            stretch=1,
        )
        self.groupHeaderCard.addGroup(
            FIF.PLAY_SOLID,
            '开始',
            '开始压缩所选图片',
            self.startBtn,
        )
        self.scrollLayout.addWidget(self.titleLabel, 0, Qt.AlignmentFlag.AlignTop)
        self.scrollLayout.addWidget(self.imageFileCard, 0, Qt.AlignmentFlag.AlignTop)
        self.scrollLayout.addWidget(self.groupHeaderCard, 0, Qt.AlignmentFlag.AlignTop)

    def __connectSignals(self):
        self.startBtn.clicked.connect(self.compressImages)
        self.saveBtn.clicked.connect(self.selectSavePath)
        self.keepRatioSwitch.checkedChanged.connect(self.onKeepRatioChanged)

    def selectSavePath(self) -> None:
        folder = QFileDialog.getExistingDirectory(self, '选择文件夹', self.savePath, QFileDialog.Option.ShowDirsOnly)
        if folder:
            self.savePath = folder
            self.savePathGroup.setContent(folder)

    def compressImages(self) -> None:
        if not self.imageFileCard.files:
            InfoBar.warning('请选择图片', '请先选择需要压缩的图片', parent=self.window())
            return
        self.load(
            compressImage,
            self.imageFileCard.files,
            self.savePath,
            size=self.sizeSettingWidget.getSize(),
            keep_ratio=self.keepRatioSwitch.isChecked(),
            quality=self.qualitySlider.value()
        )

    def onFuncSuccess(self, result: Any):
        InfoBar.success('压缩成功', f'压缩完成, 压缩后的图片保存在 {self.savePath}', duration=3000,
                        parent=self.window())

    def onKeepRatioChanged(self, isChecked: bool):
        if isChecked:
            self.keepRatioSwitch.setText('保持比例')
        else:
            self.keepRatioSwitch.setText('不保持比例')
